package main

import (
	"fmt"
)

//API is interface
type API interface {
	Say(name string) string
	GetName() string
}

//NewAPI return Api instance by type
func NewAPI(t int) API {
	if t == 1 {
		return &hiAPI{
			Name: "haha",
		}
	} else if t == 2 {
		return &helloAPI{
			Name: "doudou",
		}
	}
	return nil
}

//hiAPI is one of API implement
type hiAPI struct {
	Name string
}

//Say hi to name
func (*hiAPI) Say(name string) string {
	return fmt.Sprintf("Hi, %s", name)
}

func (h *hiAPI) GetName() string {
	return fmt.Sprintf("Hi, %s", h.Name)
}

//HelloAPI is another API implement
type helloAPI struct {
	Name string
}

//Say hello to name
func (*helloAPI) Say(name string) string {
	return fmt.Sprintf("Hello, %s", name)
}

func (h *helloAPI) GetName() string {
	return fmt.Sprintf("Hi, %s", h.Name)
}

//TestType1 test get hiapi with factory
func TestType11() {
	api := NewAPI(1)
	s := api.Say("Tom")
	fmt.Println(api.GetName())
	if s != "Hi, Tom" {
		fmt.Println("Type1 test fail")
	} else {
		fmt.Println(s)
	}
}

func TestType22() {
	api := NewAPI(2)
	s := api.Say("Tom")
	fmt.Println(api.GetName())
	if s != "Hello, Tom" {
		fmt.Println("Type2 test fail")
	} else {
		fmt.Println(s)
	}
}

func main() {
	TestType11()
	TestType22()
}

/*
工厂方法（Factory Method）模式：定义一个用于创建产品的接口，由子类决定生产什么产品。

优点和缺点
优点：
工厂类包含必要的逻辑判断，可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责，很方便的创建出相应的产品。工厂和产品的职责区分明确。
客户端无需知道所创建具体产品的类名，只需知道参数即可。
也可以引入配置文件，在不修改客户端代码的情况下更换和添加新的具体产品类。
缺点：
简单工厂模式的工厂类单一，负责所有产品的创建，职责过重，一旦异常，整个系统将受影响。且工厂类代码会非常臃肿，违背高聚合原则。
使用简单工厂模式会增加系统中类的个数（引入新的工厂类），增加系统的复杂度和理解难度
系统扩展困难，一旦增加新产品不得不修改工厂逻辑，在产品类型较多时，可能造成逻辑过于复杂
简单工厂模式使用了 static 工厂方法，造成工厂角色无法形成基于继承的等级结构。
应用场景
对于产品种类相对较少的情况，考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数，不需要关心如何创建对象的逻辑，可以很方便地创建所需产品。


# 简单工厂模式

go 语言没有构造函数一说，所以一般会定义NewXXX函数来初始化相关类。
NewXXX 函数返回接口时就是简单工厂模式，也就是说Golang的一般推荐做法就是简单工厂。

在这个simplefactory包中只有API 接口和NewAPI函数为包外可见，封装了实现细节。

*/
